import pandas as pd
import os
import sys
import chardet
from tkinter import Tk, messagebox

def show_feedback_and_exit(message_type, title, message):
    """显示一个弹窗并退出程序。"""
    root = Tk()
    root.withdraw()
    root.attributes('-topmost', True)
    if message_type == 'error':
        messagebox.showerror(title, message)
    else:
        messagebox.showinfo(title, message)
    root.destroy()
    sys.exit()

def get_application_path():
    """获取程序运行的根目录。"""
    try:
        if getattr(sys, 'frozen', False):
            return os.path.dirname(sys.executable)
        else:
            return os.path.dirname(os.path.abspath(__file__))
    except NameError:
        return os.getcwd()

def read_csv_with_chardet(file_path):
    """使用 chardet 自动检测文件编码并读取CSV。"""
    try:
        with open(file_path, 'rb') as f:
            result = chardet.detect(f.read())
            detected_encoding = result['encoding'] if result['confidence'] > 0.5 else 'utf-8'
        return pd.read_csv(file_path, encoding=detected_encoding, skipinitialspace=True)
    except Exception:
        raise UnicodeError(f"文件 {os.path.basename(file_path)} 的编码格式无法被自动识别或文件内容有误。")

def find_input_files(app_path, output_filename):
    """
    在程序目录中自动查找输入文件，并排除掉输出文件。
    """
    all_files = os.listdir(app_path)
    
    excel_files = [
        f for f in all_files 
        if f.lower().endswith(('.xlsx', '.xls')) 
        and not f.startswith('~') 
        and f.lower() != output_filename.lower()
    ]
    
    csv_files = [f for f in all_files if f.lower().endswith('.csv')]

    # 1. 验证Excel文件数量
    if len(excel_files) != 1:
        error_message = f"程序需要且仅需要一个Excel文件作为FB数据报告（不能是 '{output_filename}'）。\n\n"
        if len(excel_files) == 0:
            error_message += "当前目录中没有找到合适的Excel输入文件。"
        else:
            error_message += f"当前找到了 {len(excel_files)} 个可能的输入文件: {', '.join(excel_files)}"
        show_feedback_and_exit('error', '文件错误', error_message)
        
    fb_report_path = os.path.join(app_path, excel_files[0])

    # 2. 验证CSV文件数量
    if len(csv_files) != 2:
        show_feedback_and_exit('error', '文件错误',
                               f"程序需要且仅需要两个CSV文件（一个配置表，一个后台数据表）。\n\n"
                               f"当前找到 {len(csv_files)} 个: {', '.join(csv_files) if csv_files else '无'}")

    # 3. 区分两个CSV文件
    csv_path1 = os.path.join(app_path, csv_files[0])
    csv_path2 = os.path.join(app_path, csv_files[1])
    
    config_file_path = None
    backend_report_path = None

    try:
        df1_head = pd.read_csv(csv_path1, nrows=0, encoding='utf-8', skipinitialspace=True).columns.tolist()
    except Exception:
        try:
             df1_head = read_csv_with_chardet(csv_path1).columns.tolist()
        except Exception as e:
             show_feedback_and_exit('error', 'CSV读取失败', f"尝试读取文件 '{csv_files[0]}' 的表头时出错，请检查文件是否损坏或格式正确。\n错误: {e}")
    try:
        df2_head = pd.read_csv(csv_path2, nrows=0, encoding='utf-8', skipinitialspace=True).columns.tolist()
    except Exception:
        try:
            df2_head = read_csv_with_chardet(csv_path2).columns.tolist()
        except Exception as e:
            show_feedback_and_exit('error', 'CSV读取失败', f"尝试读取文件 '{csv_files[1]}' 的表头时出错，请检查文件是否损坏或格式正确。\n错误: {e}")

    # 【已修改】配置文件现在只要求包含'渠道'列
    config_cols = {'渠道'}
    is_df1_config = config_cols.issubset(set(df1_head))
    is_df2_config = config_cols.issubset(set(df2_head))

    if is_df1_config and not is_df2_config:
        config_file_path = csv_path1
        backend_report_path = csv_path2
    elif not is_df1_config and is_df2_config:
        config_file_path = csv_path2
        backend_report_path = csv_path1
    elif is_df1_config and is_df2_config:
        show_feedback_and_exit('error', '文件混淆',
                               f"无法区分配置文件和后台数据文件。\n"
                               f"文件 '{csv_files[0]}' 和 '{csv_files[1]}' 都被识别为了配置文件（都包含'渠道'列）。\n\n"
                               "请确保后台数据文件中不包含名为 '渠道' 的列。")
    else:
        show_feedback_and_exit('error', '文件缺失',
                               f"在找到的两个CSV文件中，没有一个能被识别为配置文件。\n\n"
                               f"配置文件现在必须且仅需包含 '渠道' 这一列。\n"
                               f"请检查文件 '{csv_files[0]}' 和 '{csv_files[1]}'。")

    return {
        'fb': fb_report_path,
        'config': config_file_path,
        'backend': backend_report_path
    }


def main():
    """主程序逻辑"""
    app_path = get_application_path()
    
    OUTPUT_FILENAME = '汇总结果.xlsx'
    
    try:
        file_paths = find_input_files(app_path, OUTPUT_FILENAME)
        config_file = file_paths['config']
        fb_report_file = file_paths['fb']
        backend_report_file = file_paths['backend']
    except Exception as e:
        show_feedback_and_exit('error', '致命错误', f"在程序初始化阶段发生未知错误: {e}")

    output_file = os.path.join(app_path, OUTPUT_FILENAME)

    try:
        df_config = read_csv_with_chardet(config_file)
        df_backend = read_csv_with_chardet(backend_report_file)
        df_fb = pd.read_excel(fb_report_file)
    except UnicodeError as e:
         show_feedback_and_exit('error', '致命编码错误', str(e) + "\n\n【解决方案】\n请用【记事本】程序打开这个出问题的CSV文件，选择“文件” -> “另存为...”，在弹出的窗口最下方找到“编码”选项，手动选择【UTF-8】后保存，然后重新运行本程序。")
    except Exception as e:
        show_feedback_and_exit('error', '文件读取错误', f"读取文件时发生错误：\n{e}")

    # --- 数据清洗 ---
    all_dfs = {'fb': df_fb, 'backend': df_backend}
    cols_to_clean_map = {
        'fb': ['已花费金额 (USD)', '点击量（全部）', '展示次数', '购物次数'],
        'backend': ['installs', 'register_events', '新客充值人数_events', '新客充值额度_revenue']
    }

    for name, df in all_dfs.items():
        for col in cols_to_clean_map.get(name, []):
            if col in df.columns:
                df[col] = pd.to_numeric(df[col], errors='coerce').fillna(0)

    # --- 核心处理逻辑 ---
    results = []
    # 【已修改】直接遍历所有渠道配置
    for index, row in df_config.iterrows():
        # 【已修改】只从配置中获取渠道
        channel = str(row['渠道'])
        
        metrics = {
            '消耗': 0, '展示': 0, '点击': 0, '购物': 0,
            '安装': 0, '注册': 0, '新客充值人数': 0, '新客充值额度': 0
        }

        # FB数据逻辑
        if '广告系列名称' in df_fb.columns:
            # 【已修改】仅通过渠道进行匹配
            mask = df_fb['广告系列名称'].astype(str).str.contains(channel, na=False)
            
            if '已花费金额 (USD)' in df_fb.columns: metrics['消耗'] = df_fb.loc[mask, '已花费金额 (USD)'].sum()
            if '点击量（全部）' in df_fb.columns: metrics['点击'] = df_fb.loc[mask, '点击量（全部）'].sum()
            if '展示次数' in df_fb.columns: metrics['展示'] = df_fb.loc[mask, '展示次数'].sum()
            if '购物次数' in df_fb.columns: metrics['购物'] = df_fb.loc[mask, '购物次数'].sum()

        # 后台数据逻辑
        if 'channel' in df_backend.columns and 'campaign_network' in df_backend.columns:
            # 【已修改】仅通过渠道进行匹配
            backend_mask = (df_backend['channel'].astype(str).str.contains('Facebook', na=False, case=False)) & \
                           (df_backend['campaign_network'].astype(str).str.contains(channel, na=False))
            
            if 'installs' in df_backend.columns: metrics['安装'] = df_backend.loc[backend_mask, 'installs'].sum()
            if 'register_events' in df_backend.columns: metrics['注册'] = df_backend.loc[backend_mask, 'register_events'].sum()
            if '新客充值人数_events' in df_backend.columns: metrics['新客充值人数'] = df_backend.loc[backend_mask, '新客充值人数_events'].sum()
            if '新客充值额度_revenue' in df_backend.columns: metrics['新客充值额度'] = df_backend.loc[backend_mask, '新客充值额度_revenue'].sum()

        # 【已修改】构造最终输出行，平台硬编码为'FB'，移除关键字
        final_row = {
            '平台': 'FB', '渠道': channel,
            '消耗': metrics['消耗'], '展示': int(metrics['展示']), '点击': int(metrics['点击']),
            '购物': int(metrics['购物']),
            '安装': int(metrics['安装']),
            '注册': int(metrics['注册']),
            '新客充值人数': int(metrics['新客充值人数']),
            '新客充值额度': metrics['新客充值额度']
        }
        results.append(final_row)
    
    # --- 生成并保存最终结果 ---
    if not results:
        show_feedback_and_exit('info', '处理完成', '配置文件中没有找到任何需要处理的渠道，或处理结果为空。')
        
    result_df = pd.DataFrame(results)
    
    # 【已修改】调整最终的列顺序，移除关键字
    final_column_order = [
        '平台', '渠道', '消耗', '展示', '点击', '购物',
        '安装', '注册', '新客充值人数', '新客充值额度'
    ]
    result_df = result_df.reindex(columns=final_column_order).fillna(0)

    try:
        result_df.to_excel(output_file, index=False)
        show_feedback_and_exit('info', '成功', f"处理完成！\n结果已保存到：\n{output_file}")
    except Exception as e:
        show_feedback_and_exit('error', '保存失败', f"无法保存结果文件 '{os.path.basename(output_file)}'。\n"
                                              f"请检查文件是否被其他程序占用。\n\n错误详情: {e}")

if __name__ == "__main__":
    main()